package com.common.login;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.common.api.annontation.ServiceLog;
import com.common.api.enums.EnableStateEnum;
import com.common.api.enums.OperateEnum;
import com.common.api.exception.CommonException;
import com.common.auth.api.dto.ResourceDto;
import com.common.auth.api.dto.UserDto;
import com.common.auth.api.dto.UserPassUpdateDto;
import com.common.auth.api.service.ResourceService;
import com.common.auth.api.service.RoleResourceService;
import com.common.auth.api.service.RoleService;
import com.common.auth.api.service.UserRoleRelationService;
import com.common.auth.api.service.UserService;
import com.common.auth.enums.ResourceTypeEnum;
import com.common.auth.error.AuthorError;
import com.common.auth.manager.PasswordManager;
import com.common.auth.po.RolePo;
import com.common.auth.po.RoleResourcePo;
import com.common.auth.po.UserPo;
import com.common.auth.po.UserRolePo;
import com.common.auth.util.AuthConstant;
import com.common.dto.LoginReqDto;
import com.common.dto.UserInfoDto;
import com.common.tools.util.BaseBusyServiceUtil;
import com.common.util.BeanCopyUtil;
import com.common.web.annotation.ControllerRequest;
import com.common.web.controller.BaseController;
import com.common.web.dto.response.RestResponse;
import com.common.web.event.LoginEvent;
import com.common.web.event.LogoutEvent;
import com.common.web.event.PreLoginEvent;
import com.common.web.event.PreLogoutEvent;
import com.common.web.service.JwtTokenUtil;
import com.common.web.util.WebConstant;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

/**
 * 权限认证服务
 * @author liuchao
 */
@ServiceLog
@ControllerRequest("/auth/")
@Api(tags = "系统授权--登录登出")
@Slf4j
public class AuthController extends BaseController{

	@Value("${sysname:先进数通软件}")
	private String sysname;
	
	@Value("${sysversion:1.0}")
	private String sysversion;
	
	@Autowired
	private JwtTokenUtil jwtTokenUtil;
	
	@Autowired
	private PasswordManager passwordManager;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private ResourceService menuService;
	
	@Autowired
	private UserRoleRelationService userRoleRelationService;
	
	@Autowired
	private RoleResourceService roleResourceService;
	
	@Autowired
	private RoleService roleService;
	
    @ApiOperation(value = "用户登录")
    @RequestMapping(value = "login")
    public RestResponse login(@RequestBody LoginReqDto loginReqDto) {
    	// 情况上次登录信息
    	try {
    		jwtTokenUtil.cleanToken(getRequest());
		} catch (Exception e) {
		}
    	String userCode=loginReqDto.getLoginname();
    	if(StringUtils.isEmpty(userCode)) {
    		throw new CommonException("用户名不能为空!");
    	}
    	// 登录前事件
    	BaseBusyServiceUtil.publicsEvent(new PreLoginEvent(userCode));
    	// 正常登录流程
    	UserPo userInfo=userService.getOne(Wrappers.lambdaQuery(UserPo.class)
    			.eq(UserPo::getEnableStateEnum,EnableStateEnum.enable.getEunmCode())
    			.eq(UserPo::getUserCode, userCode));
    	if(userInfo==null) {
    		throw new CommonException(AuthorError.userNoExist);
    	}
    	String password=loginReqDto.getPassword();
    	if(StringUtils.isEmpty(password)) {
    		throw new CommonException("密码不能为空!");
    	}
    	boolean flag=passwordManager.validataPassword(password, userInfo.getPassword(), userCode);
    	if(!flag) {
    		throw new CommonException(AuthorError.codeOrPassowrdError);
    	}
    	userInfo.setPassword(null);
    	String token=jwtTokenUtil.generateToken(userCode, userInfo.getUserName());
    	
    	// 设置返回信息
    	List<ResourceDto> resourceList=new ArrayList<>();
    	List<RolePo> roleList = new ArrayList<>();
    	UserInfoDto userInfoDto=BeanCopyUtil.map(userInfo, UserInfoDto.class);
    	userInfoDto.setToken(token);
		//
		// 获取用户角色
		UserRolePo userRolePo=new UserRolePo();
		userRolePo.setUserCode(userCode);
		List<UserRolePo> userRoleList=userRoleRelationService.list(Wrappers.query(userRolePo));
		if (CollectionUtils.isEmpty(userRoleList)) {
			throw new CommonException("请先给当前登录用户分配角色和权限后再登录！");
		}
		boolean roleAdmin = userRoleList.stream()
				.anyMatch(userRole -> AuthConstant.ADMIN_ROLE.equals(userRole.getRoleCode()));
		if(roleAdmin) {
			roleList = roleService.list(Wrappers.lambdaQuery(RolePo.class)
					.eq(RolePo::getRoleCode, AuthConstant.ADMIN_ROLE));
			resourceList=menuService.queryTreeList();
		}else {
			List<String> roleCodeList=userRoleList.stream().map(UserRolePo::getRoleCode).collect(Collectors.toList());
			if(CollectionUtils.isNotEmpty(roleCodeList)) {
				// 查询角色列表
				roleList=roleService.list(Wrappers.lambdaQuery(RolePo.class)
						.in(RolePo::getRoleCode, roleCodeList)
						.eq(RolePo::getEnableStateEnum, EnableStateEnum.enable.getEunmCode()));
				if (CollectionUtils.isEmpty(roleList)) {
					throw new CommonException("请为当前登录用户至少启用一个角色！");
				}
				List<String> roleListCol =roleList.stream()
						.map(RolePo::getRoleCode)
						.collect(Collectors.toList());
				// 获取角色资源
				LambdaQueryWrapper<RoleResourcePo> roleResource = Wrappers.lambdaQuery(RoleResourcePo.class);
				roleResource.in(RoleResourcePo::getRoleCode, roleListCol);
				List<RoleResourcePo> reloResourceList=roleResourceService.getBaseMapper().selectList(roleResource);
				List<String> resourceCodeList=reloResourceList.stream().map(RoleResourcePo::getResourceCode)
						.collect(Collectors.toList());
				if (CollectionUtils.isEmpty(reloResourceList)) {
					throw new CommonException("请先给当前登录用户分配权限资源！");
				}
				resourceList=menuService.queryTreeList(resourceCodeList);
				if (CollectionUtils.isEmpty(resourceList)) {
					throw new CommonException("请先启用当前登录用户的资源权限！");
				}
			}
		}
		userInfoDto.setResourceList(resourceList);
		userInfoDto.setRoleList(roleList);
		// 设置权限信息
		List<String> authoityList = new ArrayList<>();
		buildAuthority(resourceList,authoityList);
		jwtTokenUtil.setAuthority(token, authoityList);
		
		// 更新用户的最后登录时间
		userInfo.setLastLoginTime(new Date());
		userService.updateById(userInfo);
		// 记录操作日志
		BaseBusyServiceUtil.addOperateLog(OperateEnum.login, userCode, userInfoDto);
		
		// 触发登录成功事件
		try {
			BaseBusyServiceUtil.publicsEvent(new LoginEvent(userCode));
		} catch (Exception e) {
			log.warn("登录成功事件处理异常:"+e.getMessage());
		}
        return RestResponse.success("用户登录成功!").setData(userInfoDto);
    }
    
    @ApiOperation(value="获取个人信息")
    @RequestMapping(value={"getUserInfo"})
	public RestResponse getUserInfo() {
		RestResponse response=RestResponse.success();
		UserInfoDto userInfoDto=new UserInfoDto();
		String token = getRequest().getHeader(WebConstant.TOKEN_KEY);
		String userCode=getUserCode();
		String userName=getUserName();
		userInfoDto.setUserCode(userCode);
		userInfoDto.setUserName(userName);
		userInfoDto.setLastLoginTime(new Date());
		
		
		// 设置返回信息
    	List<ResourceDto> resourceList=new ArrayList<>();
    	List<RolePo> roleList = new ArrayList<>();
    	userInfoDto.setToken(token);
		//
		// 获取用户角色
		UserRolePo userRolePo=new UserRolePo();
		userRolePo.setUserCode(userCode);
		List<UserRolePo> userRoleList=userRoleRelationService.list(Wrappers.query(userRolePo));
		if (CollectionUtils.isEmpty(userRoleList)) {
			throw new CommonException("请先给当前登录用户分配角色和权限后再登录！");
		}
		boolean roleAdmin = userRoleList.stream()
				.anyMatch(userRole -> AuthConstant.ADMIN_ROLE.equals(userRole.getRoleCode()));
		if(roleAdmin) {
			roleList = roleService.list(Wrappers.lambdaQuery(RolePo.class)
					.eq(RolePo::getRoleCode, AuthConstant.ADMIN_ROLE));
			resourceList=menuService.queryTreeList();
		}else {
			List<String> roleCodeList=userRoleList.stream().map(UserRolePo::getRoleCode).collect(Collectors.toList());
			if(CollectionUtils.isNotEmpty(roleCodeList)) {
				// 查询角色列表
				roleList=roleService.list(Wrappers.lambdaQuery(RolePo.class)
						.in(RolePo::getRoleCode, roleCodeList)
						.eq(RolePo::getEnableStateEnum, EnableStateEnum.enable.getEunmCode()));
				if (CollectionUtils.isEmpty(roleList)) {
					throw new CommonException("请为当前登录用户至少启用一个角色！");
				}
				List<String> roleListCol =roleList.stream()
						.map(RolePo::getRoleCode)
						.collect(Collectors.toList());
				// 获取角色资源
				LambdaQueryWrapper<RoleResourcePo> roleResource = Wrappers.lambdaQuery(RoleResourcePo.class);
				roleResource.in(RoleResourcePo::getRoleCode, roleListCol);
				List<RoleResourcePo> reloResourceList=roleResourceService.getBaseMapper().selectList(roleResource);
				List<String> resourceCodeList=reloResourceList.stream().map(RoleResourcePo::getResourceCode)
						.collect(Collectors.toList());
				if (CollectionUtils.isEmpty(reloResourceList)) {
					throw new CommonException("请先给当前登录用户分配权限资源！");
				}
				resourceList=menuService.queryTreeList(resourceCodeList);
				if (CollectionUtils.isEmpty(resourceList)) {
					throw new CommonException("请先启用当前登录用户的资源权限！");
				}
			}
		}
		userInfoDto.setResourceList(resourceList);
		userInfoDto.setRoleList(roleList);
		// 设置权限信息
		List<String> authoityList = new ArrayList<>();
		buildAuthority(resourceList,authoityList);
		jwtTokenUtil.setAuthority(token, authoityList);
		return response.setData(userInfoDto);
	}
    
    @ApiOperation(value = "修改密码")
    @RequestMapping(value = "updatePassword")
    public RestResponse updatePassword(@RequestBody UserPassUpdateDto dto) {
    	String usercode=dto.getUserCode();
    	UserDto userInfo=userService.get(usercode);
    	if(userInfo==null) {
    		throw new CommonException(AuthorError.userNoExist);
    	}
    	String password=dto.getOldPassword();
    	boolean flag=passwordManager.validataPassword(password, userInfo.getPassword(), usercode);
    	if(!flag) {
    		throw new CommonException(AuthorError.codeOrPassowrdError);
    	};
        userService.updatePassword(dto);
		BaseBusyServiceUtil.addOperateLog(OperateEnum.changePwd, getUserCode(), "");
        return RestResponse.success("修改用户密码成功!");
    }
    
    @ApiOperation(value = "用户退出")
    @RequestMapping(value = "logout")
    public RestResponse logout() {
    	String userCode = getUserCode();
    	// 退出前事件
    	BaseBusyServiceUtil.publicsEvent(new PreLogoutEvent(userCode));
    	//添加日志
    	BaseBusyServiceUtil.addOperateLog(OperateEnum.logout, userCode, null);
    	jwtTokenUtil.cleanToken(getRequest());
		// 触发退出成功事件
		try {
			BaseBusyServiceUtil.publicsEvent(new LogoutEvent(userCode));
		} catch (Exception e) {
			log.warn("退出成功事件处理异常:"+e.getMessage());
		}
        return RestResponse.success("用户退出成功!");
    }
    
    @ApiOperation(value = "获取系统信息")
    @RequestMapping(value = "getSysInfo")
    public RestResponse getSysInfo() {
      	// 调用登录前事件
    	BaseBusyServiceUtil.publicsEvent(new PreLoginEvent(""));
    	// 正常业务出来
    	RestResponse response=RestResponse.success();
    	Map<String,String> data=new HashMap<>();
		data.put("systemName", sysname);
		data.put("systemVersion", sysversion);
    	response.setData(data);
    	return response;
    }
    
    /**
     * 设置权限信息
     * @param resourceList
     */
    private void buildAuthority(List<ResourceDto> resourceList,List<String> authoityList) {
    	if(CollectionUtils.isEmpty(resourceList)) {
    		return ;
    	}
    	resourceList.forEach(item->{
    		String menuType = item.getResourceType();
    		String permsId = item.getResourceCode();
    		if(ResourceTypeEnum.button.getEunmCode().equals(menuType)
    				&&StringUtils.isNoneEmpty(permsId)) {
    			authoityList.add(permsId);
    		}
    		List<ResourceDto> children = item.getChildren();
    		buildAuthority(children,authoityList);
    	});
    }
    
}
